using System;
using WaveLib;
using System.Runtime.InteropServices;

namespace SharpWind.Network
{
	/// <summary>
	/// Based on CodeProject Article
	/// see: http://www.codeproject.com/cs/media/cswavrec.asp?df=100&forumid=16677&exp=0&select=2002254
	/// And GibPhone Speex Plugin
	/// see: http://sourceforge.net/project/showfiles.php?group_id=148436
	/// </summary>
	public class Voice : IDisposable
	{
		#region Fields

		private WaveInRecorder microphone = null;

		private WaveOutPlayer speaker = null;

		private WaveFormat format = null;

		private FifoStream fifo = null;

		private byte[] buffer = null;

		private int bufferSize = 4096;

		private bool lastPassed = false;

		private byte[] playBuffer = null;

		private int threshold = 32000;

		#endregion

		#region Events

		public event VoiceEventHandler VoiceCaptured = null;

		#endregion

		#region Constructor

		public Voice( int sampleSize, int sampleRate, int channels )
		{
			this.fifo = new FifoStream();

			this.format		= new WaveFormat( sampleRate, sampleSize, channels );
			this.microphone = new WaveInRecorder( -1, this.format, this.bufferSize, 3, new BufferDoneEventHandler( DataArrived ) );
			this.speaker	= new WaveOutPlayer( -1, this.format, this.bufferSize, 3, new BufferFillEventHandler( Filler ) );
		}

		#endregion

		#region Methods

		public void Playback( byte[] buffer )
		{
			if( buffer != null )
			{
				this.fifo.Write( buffer, 0, buffer.Length );
			}
		}

		private void DataArrived( IntPtr data, int size )
		{
			if( VoiceCaptured != null )
			{
				this.buffer = new byte[size];
				Marshal.Copy( data, buffer, 0, size );

				VoiceCaptured( this, new VoiceEventArgs( buffer ) );

				/*long Sum = 0;
				int n = size / 2;
				for( int i = 0; i < n; i++ )
				{
					int LSB = buffer[2 * i];
					int MSB = buffer[( 2 * i ) + 1];
					int Sample = ( ( MSB & 0x7f ) << 8 ) | ( 0xff & LSB );
					Sum += Sample;
				}

				long Avg = Sum / ( (long)n );
				bool passed = Avg < threshold;
				if( passed || this.lastPassed )
				{
					
				}
				else
				{
					//Console.WriteLine( "didnt pass- " + Avg );
				}

				this.lastPassed = passed;*/
			}
		}

		private void Filler( IntPtr data, int size )
		{
			if( this.playBuffer == null || this.playBuffer.Length < size )
			{
				this.playBuffer = new byte[size];
			}

			if( this.fifo.Length >= size )
			{
				this.fifo.Read( playBuffer, 0, size );
			}
			else
			{
				for( int i = 0; i < playBuffer.Length; i++ )
				{
					playBuffer[i] = 0;
				}
			}

			Marshal.Copy( this.playBuffer, 0, data, size );
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			if( this.microphone != null )
			{
				this.microphone.Dispose();
				this.microphone = null;
			}

			if( this.speaker != null )
			{
				this.fifo.Flush();
				this.speaker.Dispose();
				this.speaker = null;
			}
		}

		#endregion
	}
}
